#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

#define KEY 22

#define PRESS_THRESHOLD 150
#define IDLE_THRESHOLD  500
// #define SPACE_THRESHOLD 1000

uint8_t isKeyPressed(void);
void RefreshKey(void);
void longClickCallback(void);
void shorClickCallback(void);
void idleCallback(void);
void spaceCallback(void);

char morse[1 << 13] = {0};
uint16_t code;
uint8_t cnt = 0;

BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
char BLEbuf[4] = {0};

#define SERVICE_UUID           "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

class MyServerCallbacks: public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) {
    deviceConnected = true;
  };

  void onDisconnect(BLEServer* pServer) {
    deviceConnected = false;
  }
};

class MyCallbacks: public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *pCharacteristic) {
    std::string rxValue = pCharacteristic->getValue();

    // if (rxValue.length() > 0) {
    //   Serial.print("------>Received Value: ");

    //   for (int i = 0; i < rxValue.length(); i++) {
    //     Serial.print(rxValue[i]);
    //   }
    //   Serial.println();
      
    //   if (rxValue.find("A") != -1) { 
    //     Serial.print("Rx A!");
    //   }
    //   else if (rxValue.find("B") != -1) {
    //     Serial.print("Rx B!");
    //   }
    //   Serial.println();
    // }
  }
};

void setup()
{
  morse[0b1101]       = 'a';
  morse[0b01010111]   = 'b';
  morse[0b01110111]   = 'c';
  morse[0b010111]     = 'd';
  morse[0b01]         = 'e';
  morse[0b01110101]   = 'f';
  morse[0b011111]     = 'g';
  morse[0b01010101]   = 'h';
  morse[0b0101]       = 'i';
  morse[0b11111101]   = 'j';
  morse[0b110111]     = 'k';
  morse[0b01011101]   = 'l';
  morse[0b1111]       = 'm';
  morse[0b0111]       = 'n';
  morse[0b111111]     = 'o';
  morse[0b01111101]   = 'p';
  morse[0b11011111]   = 'q';
  morse[0b011101]     = 'r';
  morse[0b010101]     = 's';
  morse[0b11]         = 't';
  morse[0b110101]     = 'u';
  morse[0b11010101]   = 'v';
  morse[0b111101]     = 'w';
  morse[0b11010111]   = 'x';
  morse[0b11110111]   = 'y';
  morse[0b01011111]   = 'z';
  morse[0b1111111101] = '1';
  morse[0b1111110101] = '2';
  morse[0b1111010101] = '3';
  morse[0b1101010101] = '4';
  morse[0b0101010101] = '5';
  morse[0b0101010111] = '6';
  morse[0b0101011111] = '7';
  morse[0b0101111111] = '8';
  morse[0b0111111111] = '9';
  morse[0b1111111111] = '0';
  morse[0b010101010101] = ' ';

  pinMode(KEY, INPUT);
  
  Serial.begin(115200);
  Serial.println("Welcolm to use Telegram Machine! Please send a message with Morse code!");

  // Create the BLE Device
	BLEDevice::init("Telegram_BLE"); 
	
	// Create the BLE Server
	BLEServer *pServer = BLEDevice::createServer();
	pServer->setCallbacks(new MyServerCallbacks());
	
	// Create the BLE Service
	BLEService *pService = pServer->createService(SERVICE_UUID);
	
	// Create a BLE Characteristic
	pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
	                 
	pCharacteristic->addDescriptor(new BLE2902());
	
	BLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
	
	pCharacteristic->setCallbacks(new MyCallbacks());
	
	// Start the service
	pService->start();
	
	// Start advertising
	pServer->getAdvertising()->start();
	Serial.println("Waiting a client connection to notify...");
}

void loop()
{
  RefreshKey();
  delay(10);
}

uint8_t isKeyPressed(void)
{
  return !digitalRead(KEY);
}

void RefreshKey(void)
{
  static uint8_t pressed;                         // 用来记录按钮是否按下
  static uint8_t click_pending;                   // 挂起标志
  // static uint8_t space_pending;
  static uint32_t press_time, release_time;       // 记录按下和松开的时间

  if (isKeyPressed())
  {
    if (pressed == 0)
    {
      press_time = millis();
    }
    pressed = 1;
  }
  else
  {
    if (pressed)
    {
      release_time = millis();
      click_pending = 1;
      // space_pending = 1;

      if (millis() - press_time > PRESS_THRESHOLD) // 长按
      {
        longClickCallback();
      }
      else
      {
        shorClickCallback();
      }
    }
    else
    {
      if (click_pending && millis() - release_time > IDLE_THRESHOLD)
      {
        idleCallback();
        click_pending = 0;
      }
      // if (space_pending && millis() - release_time > SPACE_THRESHOLD)
      // {
      //   spaceCallback();
      //   space_pending = 0;
      // }
    }
    pressed = 0;
  }
}

void longClickCallback(void)
{
  code |= 0b11 << (2 * cnt);
  ++cnt;
}

void shorClickCallback(void)
{
  code |= 0b01 << (2 * cnt);
  ++cnt;
}

void idleCallback(void)
{
  if (code == 0b111111111111)
  {
    Serial.println();
    if (deviceConnected)
    {
      memset(BLEbuf, 0, 4);
		  memcpy(BLEbuf, (char*)"\r\n", 2); 
		  pCharacteristic->setValue(BLEbuf);
      pCharacteristic->notify();
    }
  }
  else
  {
    char msg = morse[code];
    // Serial.println(code);
    Serial.print(msg);

    if (deviceConnected)
    {
      memset(BLEbuf, 0, 4);
		  memcpy(BLEbuf, &msg, 1); 
		  pCharacteristic->setValue(BLEbuf);
      pCharacteristic->notify();
    }

    cnt = 0;
    code = 0;
  }
}

void spaceCallback(void)
{
  Serial.print(" ");
}